package com.link.base.base.sms.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.link.base.base.mpconfig.dao.mybatis.mapper.MpMapper;
import com.link.base.base.mpconfig.model.Mp;
import com.link.base.base.mpconfig.model.SendTempMessage;
import com.link.base.base.mpconfig.model.TemplateData;
import com.link.base.base.mpconfig.service.MpService;
import com.link.base.base.mpconfig.service.MpTokenService;
import com.link.base.base.mpconfig.service.SendTempMessageService;
import com.link.base.base.sms.dao.mybatis.mapper.SendResultMapper;
import com.link.base.base.sms.dao.mybatis.mapper.TemplateMapper;
import com.link.base.base.sms.model.MsgResult;
import com.link.base.base.sms.model.MsgTemplate;
import com.link.base.base.sms.model.PushSms;
import com.link.base.base.user.service.UserService;
import com.link.base.base.wechat.model.TemTable;
import com.link.base.base.wechat.service.TableService;
import com.link.base.microinterface.microservice.MemberClient;
import com.link.base.sms.model.*;
import com.link.base.user.model.CoreUser;
import com.link.base.wechat.basic.util.WeixinHttpUtil;
import com.link.base.wechat.basic.util.WxExceptionUtil;
import com.link.base.wechat.wxmessage.model.TempData;
import com.link.base.wechat.wxplatform.model.WxPlatform;
import com.link.base.wechat.wxplatform.service.WxPlatformService;
import com.link.base.wechat.wxtoken.model.WxToken;
import com.link.base.wechat.wxtoken.service.WxTokenService;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.interceptor.SecurityInterceptor;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.ServiceException;
import com.link.core.cllog.LCLogger;
import com.link.core.util.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @Author: liulu
 * @Date:15:37 2018/11/5
 */
@Service
public class TemplateServiceImpl extends BasicServiceImpl<Template> implements TemplateService {

    private static final Logger logger = LogManager.getLogger(TemplateServiceImpl.class);

    @Resource
    private Environment env;

    @Resource
    private TemplateMapper templateMapper;

    @Resource
    private MsgResultService msgResultService;

    @Resource
    private PushSmsService pushSmsService;

    @Resource
    private MpTokenService mpTokenService;

    @Resource
    private WxTokenService wxTokenService;

    @Resource
    private MpService mpService;

    @Resource
    private SendTempMessageService sendTempMessageService;

    @Resource
    private MpMapper mpMapper;

    @Resource
    private TableService tableService;

    @Resource
    private WxPlatformService wxPlatformService;

    @Resource
    private MemberClient memberClient;

    @Resource
    private UserService userService;

    @Resource
    private SignatureService signatureService;

    @Resource
    private SendResultMapper sendResultMapper;

    @Resource
    private SmsSendService smsSendService;


    /**
     * 消息类型-短信
     */
    public static final String MSG_TYPE_SMS = "SMS";
    /**
     * 消息类型-小程序
     */
    public static final String MSG_TYPE_MP = "MiniProgram";
    /**
     * 消息类型-公众号
     */
    public static final String MSG_TYPE_WX = "OfficialAccount";
    /**
     * 发送类型-立即发送
     */
    public static final String SEND_TYPE_IMMEDIATELY = "Immediately";
    /**
     * 消息状态-发送失败
     */
    public static final String MESSAGE_STATUS_FAILED = "Failed";
    /**
     * 消息状态-发送成功
     */
    public static final String MESSAGE_STATUS_SUCCEEDED = "Succeeded";

    @Override
    public BasicMapper<Template> getBasicMapper() {
        return templateMapper;
    }

    @Override
    public void beforInsert(Template entity) throws Exception {
        CoreUser loginUser = UserUtil.getUser();
        String smsSynToTencent = PropertyUtil.getProperty("smsSynToTencent", loginUser.getLoginCorpId());
        if ("Y".equals(smsSynToTencent)) {
            JSONObject jsonParam = new JSONObject();
            this.syncTencent(entity, "https://yun.tim.qq.com/v5/tlssmssvr/add_template", jsonParam);
        }
    }

    @Override
    public void beforUpdate(Template entity) throws Exception {
        CoreUser loginUser = UserUtil.getUser();
        String smsSynToTencent = PropertyUtil.getProperty("smsSynToTencent", loginUser.getLoginCorpId());
        if ("Y".equals(smsSynToTencent)) {
            if (!"notSync".equals(entity.getAttr1()) && null != entity.getTemplID()) {
                JSONObject jsonParam = new JSONObject();
                jsonParam.put("tpl_id", entity.getTemplID());
                this.syncTencent(entity, "https://yun.tim.qq.com/v5/tlssmssvr/mod_template", jsonParam);
            }
        }
    }

    /**
     * @author 王艳
     * @zhushi: 短信模板新增或修改时同步至腾讯云
     */
    public void syncTencent(Template entity, String url, JSONObject jsonParam) throws Exception {
        Long time = DateUtil.getCurrentLongTime() / 1000;
        Random rd = new Random();
        String random = "";
        int rdLength = 10;
        for (int i = 0; i < rdLength; i++) {
            random += String.valueOf(rd.nextInt(10));
        }
        CoreUser loginUser = UserUtil.getUser();
        String sig = PasswordUtil.getSHA256StrJava("appkey="
                + PropertyUtil.getProperty("tencentAppKey", loginUser.getLoginCorpId())
                + "&random=" + random + "&time=" + time.toString());
        jsonParam.put("sig", sig);
        jsonParam.put("text", entity.getText());
        jsonParam.put("title", entity.getTitle());
        jsonParam.put("time", time);
        //短信按类型进行区分
        String type = entity.getType();
        int tencentType = 0;
        switch (type) {
            case "CommonSMS":
                tencentType = 0;
                break;
            case "MarketingSMS":
                tencentType = 1;
                break;
            default:
                break;
        }

        jsonParam.put("type", tencentType);
        String resultParams = HttpUtils.sendPost(url + "?sdkappid="
                + Integer.parseInt(PropertyUtil.getProperty("tencentAppId", loginUser.getLoginCorpId()))
                + "&random=" + random, JSONObject.toJSONString(jsonParam));
        JSONObject result = JSONObject.parseObject(resultParams);

        if (null == result) {
            throw new ServiceException("SMS-005");
        } else {
            if (!"0".equals(result.get("result").toString())) {
                String errorMsg = result.getString("msg");
                throw new ServiceException(errorMsg);
            } else {
                String syncTime = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
                String data = result.getString("data");
                JSONObject resultData = JSONObject.parseObject(data);
                // 模板 id
                String id = resultData.getString("id");
                if (!StringUtils.isBlank(id)) {
                    entity.setTemplID(Integer.valueOf(id));
                    // 更新模板状态为 待审核
                    entity.setStatus("UnderReview");
                    //entity.setSyncTime(syncTime);
                }
            }
        }
    }

    /**
     * @author 王艳
     * @zhushi: 短信模板同步腾讯云状态
     */
    @Override
    public void syncTencentStatus() throws Exception {
        List<Integer> list = templateMapper.queryTemplIdByStatus();
        if (list.size() == 0) {
            return;
        }
        Long time = DateUtil.getCurrentLongTime() / 1000;
        Random rd = new Random();
        String random = "";
        int rdLength = 10;
        for (int i = 0; i < rdLength; i++) {
            random += String.valueOf(rd.nextInt(10));
        }
        CoreUser loginUser = UserUtil.getUser();
        String sig = PasswordUtil.getSHA256StrJava("appkey="
                + PropertyUtil.getProperty("tencentAppKey", loginUser.getLoginCorpId()) + "&random=" + random + "&time=" + time.toString());
        JSONObject jsonParam = new JSONObject();
        JSONObject tpl_page = new JSONObject();
        tpl_page.put("max", 50);
        tpl_page.put("offset", 0);
        jsonParam.put("sig", sig);
        jsonParam.put("time", time);
        jsonParam.put("tpl_page", tpl_page);
        int pageSize = 50;
        int totalCount = list.size();
        int pageCount = 0;
        int m = totalCount % pageSize;
        if (m > 0) {
            pageCount = totalCount / pageSize + 1;
        } else {
            pageCount = totalCount / pageSize;
        }

        for (int i = 1; i <= pageCount; i++) {
            List<Integer> subList;
            if (m == 0) {
                subList = list.subList((i - 1) * pageSize, pageSize * (i));
            } else {
                if (i == pageCount) {
                    subList = list.subList((i - 1) * pageSize, totalCount);
                } else {
                    subList = list.subList((i - 1) * pageSize, pageSize * (i));
                }
            }

            jsonParam.put("tpl_id", subList.toArray());
            String resultParams = HttpUtils.sendPost("https://yun.tim.qq.com/v5/tlssmssvr/get_template?sdkappid="
                    + Integer.parseInt(PropertyUtil.getProperty("tencentAppId", loginUser.getLoginCorpId()))
                    + "&random=" + random, JSONObject.toJSONString(jsonParam));
            JSONObject result = JSONObject.parseObject(resultParams);

            if (null == result) {
                throw new ServiceException("SMS-005");
            } else {
                if (!"0".equals(result.get("result").toString())) {
                    String errorMsg = result.getString("msg");
                    continue;
                } else {
                    String syncTime = DateUtil.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
                    String data = result.getString("data");
                    JSONArray resultData = JSONObject.parseArray(data);
                    for (Object object : resultData) {
                        JSONObject jsonObject = JSONObject.parseObject(object.toString());
                        String id = jsonObject.getString("id");
                        if (!StringUtils.isBlank(id)) {
                            Template entity = new Template();
                            entity.setTemplID(Integer.valueOf(id));
                            String status = jsonObject.getString("status");
                            entity.setStatus(getStatus(status));
                            /*if ("2".equals(status) && jsonObject.containsKey("reply")) {
                                String reply = jsonObject.getString("reply");
                                entity.setReply(reply);
                            }
                            entity.setSyncTime(syncTime);*/
                            templateMapper.statusUpdate(entity);
                        }
                    }
                }
            }
        }
    }

    /**
     * @author 王艳
     * @zhushi: 匹配状态
     */
    @Override
    public String getStatus(String status) {
        if ("0".equals(status)) {
            // 更新模板状态为 已通过
            status = "Approved";
        } else if ("1".equals(status)) {
            // 更新模板状态为 待审核
            status = "UnderReview";
        } else if ("2".equals(status)) {
            // 更新模板状态为 已拒绝
            status = "Rejected";
        }
        return status;
    }

    @Override
    public String toTemplateJsonString(Template record, String openId, String formId,
                                       Map<String, Object> paramMap, String defaultPage) throws Exception {
        if (openId == null) {
            throw new BasicServiceException("openId不能为空");
        }
        List<String> params = new ArrayList<String>();
        params.add(record.getParameter1());
        params.add(record.getParameter2());
        params.add(record.getParameter3());
        params.add(record.getParameter4());
        params.add(record.getParameter5());
        params.add(record.getParameter6());
        params.add(record.getParameter7());
        params.add(record.getParameter8());
        params.add(record.getParameter9());
        params.add(record.getParameter10());
        /**
         * 将参数写入到paramJson对象中
         */
        JSONObject paramJson = new JSONObject();
        paramJson.put("touser", openId);
        paramJson.put("template_id", record.getTemplateId());

        if (MSG_TYPE_MP.equals(record.getType())) {
            // 微信小程序-FormId
            if (StringUtils.isBlank(formId)) {
                throw new BasicServiceException("小程序模板消息：form_id不能为空");
            }
            paramJson.put("form_id", formId);
        }

        String linkedPage = defaultPage;
        if (StringUtils.isNotBlank(record.getAttr3())) {
            linkedPage = record.getAttr3();
        }
        if (linkedPage != null) {
            paramJson.put("page", linkedPage);
        }

        String delimiterRegex = "\\|";

        Map<String, TemplateData> dataMap = new HashMap<>();
        // 微信公众号-消息说明
        if (StringUtils.isNotBlank(record.getFirst())) {
            String[] firstArr = record.getFirst().split(delimiterRegex);
            TemplateData templateData = new TemplateData(firstArr[0]);
            if (firstArr.length > 1) {
                templateData.setColor(firstArr[1]);
            }
            dataMap.put("first", templateData);
        }
        // 微信公众号-详细信息
        if (StringUtils.isNotBlank(record.getRemark())) {
            String[] remarkArr = record.getRemark().split(delimiterRegex);
            TemplateData templateData = new TemplateData(remarkArr[0]);
            if (remarkArr.length > 1) {
                templateData.setColor(remarkArr[1]);
            }
            dataMap.put("remark", templateData);
        }
        for (String param : params) {
            if (StringUtils.isBlank(param)) {
                break;
            }
            // 切分颜色
            String[] paramSplit = param.split(delimiterRegex);
            String color = null;
            if (paramSplit.length > 1) {
                color = paramSplit[1];
            }
            // 切分参数字段
            String[] paramArr = paramSplit[0].split(":");
            if (paramArr.length < 2) {
                throw new BasicServiceException("参数配置异常：" + param);
            }
            // 消息模板参数data中keyword
            String jsonKey = paramArr[0];
            /**
             * 参数param有两种：
             * 固定文本 => keyword+序号:固定文本|颜色【keyword0:谢谢使用|#000000】
             * 系统字段 => keyword+序号:产品:产品名称|颜色【keyword1:Prod:prodName|#000000】
             */
            TemplateData keyword = new TemplateData();
            keyword.setColor(color);
            if (paramArr.length == 2) {
                keyword.setValue(paramArr[1]);
            } else {
                // 参数paramMap中key值, 即对象model名
                String paramKey = paramArr[1];
                // 对象中定义的字段名称
                String fieldName = paramArr[2];
                if (!paramMap.containsKey(paramKey)) {
                    throw new BasicServiceException("模板参数中未发现key值：【" + paramKey + "】");
                }
                Object obj = paramMap.get(paramKey);
                /*String getMethodName = "getParameter" + index;
                Method getMethod = Template.class.getMethod(getMethodName);*/
                if (obj == null) {
                    throw new BasicServiceException("模板参数中对象【" + paramKey + "】为空");
                }
                //服务间调用的情况， 这个obj可能为 jsonobject 也可能为hashmap。所以对于这样的情况，单独做处理
                if (obj instanceof JSONObject) {
                    String val = ((JSONObject) obj).get(fieldName).toString();
                    if (val == null) {
                        throw new BasicServiceException("模板参数中对象【" + paramKey + "】中不存在字段 【" + fieldName + "】");
                    }
                    keyword.setValue(val);
                } else {
                    Field field = obj.getClass().getDeclaredField(fieldName);
                    if (field == null) {
                        throw new BasicServiceException("模板参数中对象【" + paramKey + "】中不存在字段 【" + fieldName + "】");
                    }
                    boolean accessible = field.isAccessible();
                    field.setAccessible(true);
                    if (field.get(obj) instanceof Double || field.get(obj) instanceof Integer) {
                        keyword.setValue(String.valueOf(field.get(obj)));
                    } else {
                        keyword.setValue((String) field.get(obj));
                    }
                    field.setAccessible(accessible);
                }
            }
            dataMap.put(jsonKey, keyword);
        }
        paramJson.put("data", dataMap);
        return paramJson.toJSONString();
    }

    @Override
    public String toTemplateJsonString(Template record, String openId, String formId, String first, String remark,
                                       List<String> params, String defaultPage) throws Exception {
        if (openId == null) {
            throw new BasicServiceException("openId不能为空");
        }
        /**
         * 将参数写入到paramJson对象中
         */
        JSONObject paramJson = new JSONObject();
        paramJson.put("touser", openId);
        paramJson.put("template_id", record.getTemplateId());

        // 微信公众号消息，无需formId
        if (StringUtils.isNotBlank(formId)) {
            paramJson.put("form_id", formId);
        }

        String linkedPage = defaultPage;
        if (!StringUtils.isNotBlank(record.getAttr3())) {
            linkedPage = record.getAttr3();
        }
        if (linkedPage != null) {
            paramJson.put("page", linkedPage);
        }
        Map<String, TemplateData> dataMap = new HashMap<>();
        if (StringUtils.isNotBlank(first)) {
            dataMap.put("first", new TemplateData(first));
        }
        if (StringUtils.isNotBlank(remark)) {
            dataMap.put("remark", new TemplateData(remark));
        }
        if (params != null && params.size() > 0) {
            for (int i = 0; i < params.size(); i++) {
                String param = params.get(i);
                dataMap.put("keyword" + (i + 1), new TemplateData(param));
            }
            paramJson.put("data", dataMap);
        }

        return paramJson.toJSONString();
    }

    @Override
    public boolean sendTemplateMessage(MsgTemplate msgTemplate) throws Exception {
        if (msgTemplate == null || msgTemplate.getSceneName() == null) {
            return false;
        }
        // 查询场景
        PushSms pushSms = pushSmsService.queryByTitle(msgTemplate.getSceneName());
        if (pushSms == null) {
            throw new BasicServiceException("请先维护场景：【" + msgTemplate.getSceneName() + "】");
        }
        String flagY = "Y";
        // 小程序
        if (flagY.equals(pushSms.getMpOpenFlag())) {
            try {
                sendMpTemplateMsg(msgTemplate, pushSms);
            } catch (Exception e) {
                LCLogger.withException(e);
            }
        }
        // 公众号
        if (flagY.equals(pushSms.getWxOpenFlag())) {
            try {
                sendWxTemplateMsg(msgTemplate, pushSms);
            } catch (Exception e) {
                LCLogger.withException(e);
            }
        }
        // 短信
        if (flagY.equals(pushSms.getPushSwitch())) {
            try {
                sendSmsTemplateMsg(msgTemplate, pushSms);
            } catch (Exception e) {
                LCLogger.withException(e);
            }
        }
        return true;
    }

    /**
     * 短信发送
     *
     * @author guguishan
     * @date 2019/9/5 09:09
     */
    private void sendSmsTemplateMsg(MsgTemplate msgTemplate, PushSms pushSms) throws Exception {
    }

    /**
     * 发送微信模板消息
     *
     * @author guguishan
     * @date 2019/9/4 14:18
     */
    private void sendWxTemplateMsg(MsgTemplate msgTemplate, PushSms pushSms) throws Exception {
        Long templateId = pushSms.getWxTempId();
        // 消息记录
        MsgResult msgResult = new MsgResult(pushSms.getId(), templateId, MSG_TYPE_WX,
                msgTemplate.getSendType(), msgTemplate.getWxOpenId(), null, msgTemplate.getAccntId());
        msgResult.setStatus("New");
        msgResult.setId(keyGenerateService.keyGenerate());
        msgResult.setOperatorId(UserUtil.getUser().getId());
        msgResultService.insert(msgResult);
        JSONObject wxResultJson = null;
        try {
            Template record = this.queryById(templateId);
            if (record == null) {
                throw new BasicServiceException("未获取到消息模板：" + templateId);
            }
            String wxJsonString = toTemplateJsonString(record,
                    msgTemplate.getWxOpenId(), null, msgTemplate.getMpTemplateMap(), null);
            msgResult.setContent(wxJsonString);
            // 消息发送类型 = 立即发送
            if (SEND_TYPE_IMMEDIATELY.equals(msgTemplate.getSendType())) {
                msgResult.setSendTime(DateUtil.dateToStr(new Date(), DateUtil.DATE_TIME));
                String wxId = record.getWxId();
                wxResultJson = sendWxTemplate(Long.parseLong(wxId), wxJsonString);
            }
        } catch (Exception e) {
            msgResult.setErrMsg(e.getMessage());
            msgResult.setStatus(MESSAGE_STATUS_FAILED);
            LCLogger.withException(e);
        }
        handleMsgResult(msgResult, wxResultJson);
    }

    /**
     * 微信公众号发送
     *
     * @author guguishan
     * @date 2019/9/4 15:17
     * @param wxId 微信公众号信息配置id
     * @param wxJsonString 模板消息发送的消息体
     */
    private JSONObject sendWxTemplate(Long wxId, String wxJsonString) throws Exception {
        WxPlatform wxPlatform = wxPlatformService.queryById(wxId);
        if (wxPlatform == null) {
            throw new BasicServiceException("未获取到id为【" + wxId + "】的微信公众号配置");
        }
        WxToken wxToken = wxTokenService.getWxAccessTokenByAppId(wxPlatform.getWx_app_id());
        if (wxToken == null) {
            throw new BasicServiceException("获取微信公众号【" + wxPlatform.getWx_app_id() + "】认证token失败");
        }
        String accessToken = wxToken.getAccess_token();
        String requestUrl = env.getProperty("weixinuri.wxTempLateMsgUrl").replace("ACCESS_TOKEN", accessToken);
        return WeixinHttpUtil.httpRequest(requestUrl, "POST", wxJsonString);
    }

    /**
     * 发送小程序模板消息
     *
     * @author guguishan
     * @date 2019/9/4 14:18
     */
    private void sendMpTemplateMsg(MsgTemplate msgTemplate, PushSms pushSms) throws Exception {
        Long templateId = pushSms.getMpTempId();
        // 消息记录
        MsgResult msgResult = new MsgResult(pushSms.getId(), templateId, MSG_TYPE_MP,
                msgTemplate.getSendType(), msgTemplate.getMpOpenId(), null, msgTemplate.getAccntId());
        msgResult.setStatus("New");
        msgResult.setId(keyGenerateService.keyGenerate());
        msgResult.setOperatorId(UserUtil.getUser().getId());
        msgResultService.insert(msgResult);
        JSONObject wxResultJson = null;
        try {
            Template record = this.queryById(templateId);
            if (record == null) {
                throw new BasicServiceException("未获取到消息模板：" + templateId);
            }
            record.setType(MSG_TYPE_MP);
            String wxJsonString = toTemplateJsonString(record,
                    msgTemplate.getMpOpenId(), msgTemplate.getFormId(), msgTemplate.getMpTemplateMap(), null);
            msgResult.setContent(wxJsonString);

            // 消息发送类型 = 立即发送
            if (SEND_TYPE_IMMEDIATELY.equals(msgTemplate.getSendType())) {
                msgResult.setSendTime(DateUtil.dateToStr(new Date(), DateUtil.DATE_TIME));
                String wxId = record.getWxId();
                wxResultJson = sendMpTemplate(Long.parseLong(wxId), wxJsonString);
            }
        } catch (Exception e) {
            msgResult.setErrMsg(e.getMessage());
            msgResult.setStatus(MESSAGE_STATUS_FAILED);
            LCLogger.withException(e);
        }
        handleMsgResult(msgResult, wxResultJson);
    }

    /**
     * 微信小程序发送
     *
     * @author guguishan
     * @date 2019/9/4 15:20
     * @param wxId 微信小程序信息配置id
     * @param wxJsonString 模板消息发送的消息体
     */
    private JSONObject sendMpTemplate(Long wxId, String wxJsonString) throws Exception {
        Mp mp = mpService.queryById(wxId);
        if (mp == null) {
            throw new BasicServiceException("未获取到id为【" + wxId + "】的微信小程序配置");
        }
        String accessToken = mpTokenService.getMpAccessToken(mp);
        String requestUrl = env.getProperty("weixinuri.sendTempMessageUrl").replace("ACCESS_TOKEN", accessToken);
        return WeixinHttpUtil.httpRequest(requestUrl, "POST", wxJsonString);
    }

    /**
     * 处理消息发送结果
     *
     * @author guguishan
     * @date 2019/9/5 11:42
     */
    private void handleMsgResult(MsgResult result, JSONObject wxResultJson) throws Exception {
        String statusCode = "0";
        String errcode = "errcode";
        // 短信
        if (MSG_TYPE_SMS.equals(result.getMsgType())) {
            ;
        } else {
            // 微信小程序/公众号
            if (wxResultJson != null) {
                if (statusCode.equals(wxResultJson.getString(errcode))) {
                    result.setStatus(MESSAGE_STATUS_SUCCEEDED);
                } else {
                    result.setStatus(MESSAGE_STATUS_FAILED);
                }
                result.setErrMsg(wxResultJson.toJSONString());
            }
        }
        msgResultService.update(result);
    }

    @Override
    public void sendScheduledSceneMessage() throws Exception {
        // 最大循环次数，防止死循环
        int limit = 1000;
        int count = 0;
        MsgResult msgResult = new MsgResult();
        // 设置当前开始执行世间，当前时间之后的消息不进行处理
        msgResult.setAttr1(DateUtil.dateToStr(new Date(), DateUtil.DATE_TIME));
        while (count++ < limit) {
            List<MsgResult> msgResults = msgResultService.querySceneMessagePage(msgResult);
            if (msgResults == null || msgResults.size() == 0) {
                break;
            }
            for (MsgResult result : msgResults) {
                try {
                    JSONObject wxResultJson = null;
                    try {
                        Long templateId = result.getTemplateId();
                        Template record = this.queryById(templateId);
                        if (record == null) {
                            throw new BasicServiceException("未获取到消息模板：" + templateId);
                        }
                        result.setSendTime(DateUtil.dateToStr(new Date(), DateUtil.DATE_TIME));
                        // 微信小程序
                        if (MSG_TYPE_MP.equals(result.getMsgType())) {
                            wxResultJson = sendMpTemplate(Long.parseLong(record.getWxId()), result.getContent());
                        }
                        // 微信公众号
                        if (MSG_TYPE_WX.equals(result.getMsgType())) {
                            wxResultJson = sendWxTemplate(Long.parseLong(record.getWxId()), result.getContent());
                        }
                        // 短信
                        if (MSG_TYPE_SMS.equals(result.getMsgType())) {
                            ;
                        }
                    } catch (Exception e) {
                        result.setErrMsg(e.getMessage());
                        result.setStatus(MESSAGE_STATUS_FAILED);
                        LCLogger.withException(e);
                    }
                    handleMsgResult(result, wxResultJson);
                } catch (Exception e) {
                    LCLogger.withException(e);
                }
            }
        }
    }

    @Override
    public void transWxTemplate(MsgTemplate msgTemplate) throws Exception {
        // 用户信息设置
        CoreUser user = UserUtil.getUser();
        if (user == null) {
            String userName = PropertyUtil.getProperty("lytDefLoginUser", msgTemplate.getLoginCorpId());
            user = userService.getUserByUsername(userName);
            SecurityInterceptor.tempUser.set(user);
        }
        Map<String, Object> mapArg = new HashMap<>(5);
        mapArg.put("user", user);
        mapArg.put("msgTemplate", msgTemplate);
        Map<String, Object> memberRet = memberClient.transWxTemplate(mapArg);
        if (!(boolean) memberRet.get("success")) {
            throw new BasicServiceException((String) memberRet.get("result"));
        }
        logger.info("发送消息loyalty返回：" + JSON.toJSONString(memberRet.get("result")));
        MsgTemplate msgTemplateArg = JSON.parseObject(JSON.toJSONString(memberRet.get("result")), MsgTemplate.class);
        sendTemplateMessage(msgTemplateArg);
    }


    /**
     * 处理消息根据短信模板发送短信
     *
     * @author 朱泊阳
     * @date 2019/10/11 19:42
     * @param objects 传入的对象列表
     * @param pushSms 短信对象
     * @param phones 需要发送的手机号
     * @param paramMap 带有需要替换至模板参数的各个对象 map格式
     */
    @Override
    public SmsSend sendTmpSms(List<Object> objects, PushSms pushSms, List<String> phones, Map<String, String> paramMap) throws Exception {
        Template template = new Template();
        template.setId(pushSms.getTemId());
        template = this.queryById(template);
        Temparameter temparameter = new Temparameter();
        //遍历传入的对象，并将其属性名与短信模板的内设置的对象的参数名相匹配,对应的属性值设置到短信模板内,发送短信
        if (null != objects && !objects.isEmpty()) {
            setObjectParameters(objects, template, temparameter);
        }
        if (null != paramMap && !paramMap.isEmpty()) {
            setParametersByMap(paramMap, template, temparameter);
        }

        //设置短信参数，发送短信
        SmsSend send = new SmsSend();
        send.setSendMode("Imidiately");
        send.setId(keyGenerateService.keyGenerate());
        send.setTemplateId(pushSms.getTemId());
        send.setSendState("New");
        // 获取当前时间
        Date nowDt = new Date();
        String nowDtStr = DateUtil.dateToStr(nowDt, "yyyy-MM-dd HH:mm:ss");
        send.setSendTime(nowDtStr);
        //设置短信模板
        send.setTemplate(template);
        //设置模板参数
        send.setTemparameter(temparameter);
        List<SmsAccntLine> smsAccntLines = new ArrayList<>();

        int sendPersonNum = 0;
        //设置手机号
        for (String phone : phones) {
            SmsAccntLine smsAccntLine = new SmsAccntLine();
            smsAccntLine.setMobilePhone1(phone);
            smsAccntLines.add(smsAccntLine);
            sendPersonNum++;
        }
        //发送人数
        send.setSendPeopleCount(sendPersonNum);
        send.setSmsAccntLineList(smsAccntLines);
        CoreUser user = UserUtil.getUser();
        Long corpId = user.getLoginCorpId();
        Signature sige = new Signature();
        //设置短信签名id
        sige.setId(pushSms.getSignatureId());
        sige.setPageFlag(false);
        sige.setDefaultdFlag("Y");
        sige.setCorpid(corpId);
        sige.setLoginCorpId(corpId);
        //查询签名信息
        Signature signature = signatureService.queryById(sige);
        send.setSignatureId(signature.getId());
        //设置短信签名内容
        send.setSigText(signature.getText());

        smsSendService.insert(send);
        List<SendResult> sendSms = null;
        //发送短信
        sendSms = SendSmsUtil.sendSms(send);
        int sendCount = 0;
        int sendCountwin = 0;
        int useCountwin = sendSms.size();
        //循环短信发送结果
        for (SendResult sendResult : sendSms) {
            sendResult.setId(keyGenerateService.keyGenerate());
            sendResult.setLoginCorpId(corpId);
            sendResult.setLoginCorpId(corpId);
            sendResult.setPostnId(0L);
            sendResult.setOrgId(0L);
            sendResultMapper.insert(sendResult);
            sendCount += sendResult.getFee();
            //失败的短信，发送成功数减一
            if (sendResult.getResult() != 0) {
                sendCountwin -= sendResult.getFee();
                useCountwin -= 1;
            }
        }
        // 更新短信结果
        send.setSendCount(sendCount);
        //更新发送成功数
        send.setSendCountWin(sendCount + sendCountwin);
        send.setSendPeopleWin(useCountwin);
        send.setCorpid(corpId);
        send.setLoginCorpId(corpId);
        send.setAnonymousFlag("Y");
        if ((sendCount + sendCountwin) > 0) {
            send.setSendState("Succeeded");
        } else {
            send.setSendState("Failed");
        }
        smsSendService.update(send);
        return send;
    }

    /**
     * 匹配对象的属性名称并获取对应属性的值
     *
     * @author 朱泊阳
     * @date 2019/10/11 19:42
     * @param object 对象
     * @param fields 对象内的属性
     * @param targetfieldName 目标属性名称
     *
     */
    private String getValue(Object object, Field[] fields, String targetfieldName) throws Exception {
        String fieldValue = null;
        for (Field field : fields) {
            // 属性名称
            String currentFieldName = field.getName();
            if (currentFieldName.equals(targetfieldName)) {
                field.setAccessible(true);
                fieldValue = String.valueOf(field.get(object));
            }
        }
        return fieldValue;
    }

    /**
     * 遍历传入的对象，并将其属性名与短信模板的内设置的对象的参数名相匹配,对应的属性值设置到短信模板内,发送短信
     *
     * @author 朱泊阳
     * @date 2019/10/11 19:42
     *
     * @param objects 对象列表
     * @param template 短信模板
     * @param temparameter 短信模板参数
     */
    private void setObjectParameters(List<Object> objects, Template template,
                                     Temparameter temparameter) throws Exception {
        //用于判断短信模板参数是否有误
        List<String> classNames = new ArrayList<>();
        for (Object object : objects) {
            Class objClass = object.getClass();
            String allClassName = objClass.getName();
            String className = allClassName.substring(allClassName.lastIndexOf(".") + 1);
            classNames.add(className);
        }
        for (Object object : objects) {
            Class objClass = object.getClass();
            String allClassName = objClass.getName();
            String className = allClassName.substring(allClassName.lastIndexOf(".") + 1);
            //匹配短息模板中的模板参数并获取对应对象的值
            String paramter1 = template.getParameter1();
            //模板内第一条类名:属性名:属性值
            temparameter.setParameter1(getParamByObj(paramter1, className, object, classNames));
            String paramter2 = template.getParameter2();
            //模板内第二条类名:属性名:属性值
            temparameter.setParameter2(getParamByObj(paramter2, className, object, classNames));
            String paramter3 = template.getParameter3();
            //模板内第三条类名:属性名:属性值
            temparameter.setParameter3(getParamByObj(paramter3, className, object, classNames));
            String paramter4 = template.getParameter4();
            //模板内第四条类名:属性名:属性值
            temparameter.setParameter4(getParamByObj(paramter4, className, object, classNames));
            String paramter5 = template.getParameter5();
            //模板内第五条类名:属性名:属性值
            temparameter.setParameter5(getParamByObj(paramter5, className, object, classNames));
            String paramter6 = template.getParameter6();
            //模板内第六条类名:属性名:属性值
            temparameter.setParameter6(getParamByObj(paramter6, className, object, classNames));
            String paramter7 = template.getParameter7();
            //模板内第七条类名:属性名:属性值
            temparameter.setParameter7(getParamByObj(paramter7, className, object, classNames));
            String paramter8 = template.getParameter8();
            //模板内第八条类名:属性名:属性值
            temparameter.setParameter8(getParamByObj(paramter8, className, object, classNames));
            String paramter9 = template.getParameter9();
            //模板内第九条类名:属性名:属性值
            temparameter.setParameter9(getParamByObj(paramter9, className, object, classNames));
            String paramter10 = template.getParameter10();
            //模板内第十条类名:属性名:属性值
            temparameter.setParameter10(getParamByObj(paramter10, className, object, classNames));
        }

    }

    /**
     * (解析对象)匹配短息模板中的模板参数并获取对应对象的值
     * @author 朱泊阳
     * @date 2019/12/12 19:42
     *
     * @param paramter 带参数的map
     * @param className 类名
     * @param classNames 类名列表
     * @param object 需要获取模板消息对应的值的传入的对象
     */
    private String getParamByObj(String paramter, String className, Object object,
                                 List<String> classNames) throws Exception {

        Class objClass = object.getClass();
        if (!StringUtils.isBlank(paramter)) {
            String[] temps = paramter.split(":");
            if (temps.length == 3) {
                //匹配模板内保存的对象
                if (className.equals(temps[1])) {
                    // 获取所有的属性数组
                    Field[] fields = objClass.getDeclaredFields();
                    //获取对应的属性的值
                    String firstValue = getValue(object, fields, temps[2]);
                    if (!StringUtils.isBlank(firstValue)) {
                        //将属性值设置到模板参数内
                        return firstValue;
                    } else {
                        return temps[2];
                    }
                } else if (classNames.contains(temps[1])) {
                    throw new Exception("短信模板参数匹配有误,找不到对应类");
                } else {
                    return null;
                }
            } else if (temps.length == 2) {
                int temp = paramter.indexOf(":");
                paramter = paramter.substring(temp + 1);
                return paramter;
            } else {
                throw new Exception("短信模板参数设置有误");
            }
        } else {
            return null;
        }
    }


    /**
     * (解析map)匹配短息模板中的模板参数并获取对应对象的值
     * @author 朱泊阳
     * @date 2019/12/12 19:42
     *
     * @param paramter 带参数的map
     * @param className 类名
     * @param paramMap 带参数的map
     * @param json 传入的带有属性名属性值的json对象
     */
    private String getParam(String paramter, String className, Map<String, String> paramMap,
                            JSONObject json) throws Exception {
        if (!StringUtils.isBlank(paramter)) {
            String[] temps = paramter.split(":");
            if (temps.length == 3) {
                //匹配模板内保存的对象
                if (className.equals(temps[1])) {
                    if (json.containsKey(temps[2])) {
                        return json.get(temps[2]).toString();
                    } else {
                        return temps[2];
                    }
                } else if (!paramMap.containsKey(temps[1])) {
                    throw new Exception("短信模板参数匹配有误,找不到对应类");
                } else {
                    return null;
                }
            } else if (temps.length == 2) {
                int temp = paramter.indexOf(":");
                paramter = paramter.substring(temp + 1);
                return paramter;
            } else {
                throw new Exception("短信模板参数设置有误");
            }
        } else {
            return null;
        }
    }

    /**
     * 遍历传入的map，并将其属性名key与短信模板的内设置的对象的参数名相匹配,对应的属性值(json格式)设置到短信模板内,发送短信
     *
     * @author 朱泊阳
     * @date 2019/10/11 19:42
     *
     * @param paramMap 带参数的map
     * @param template 短信模板
     * @param temparameter 短信模板参数
     */
    private void setParametersByMap(Map<String, String> paramMap, Template template,
                                    Temparameter temparameter) throws Exception {
        Set<Map.Entry<String, String>> entrySet = paramMap.entrySet();
        for (Map.Entry<String, String> e : entrySet) {
            String className = e.getKey();
            JSONObject json = JSONObject.parseObject(e.getValue());
            //匹配短息模板中的模板参数并获取对应对象的值
            String paramStrPrefix = "parameter";
            for (int i = 1; i <= 10; i++) {
                String paramValue = (String) ReflectUtil.invokeGetter(temparameter, paramStrPrefix + i);
                if (StringUtils.isNotBlank(paramValue)) {
                    continue;
                }
                // 目标字段值
                String param1;
                if ("AlertRecord".equals(className)) {
                    // 预警列表使用的短信模板，因为是在预警列表页指定的短信参数字段名，所以没走通用流程设置短信参数
                    param1 = json.getString("alertParam" + i);
                } else {
                    // 目标字段名
                    String paramter1 = (String) ReflectUtil.invokeGetter(template, paramStrPrefix + i);
                    param1 = getParam(paramter1, className, paramMap, json);
                }
                ReflectUtil.invokeSetter(temparameter, paramStrPrefix + i, param1);
            }
        }
    }

    @Override
    public void sendTempMsgForAct(Long actId, Long templateId,
                                  String wxAppId, String openId, String formId) throws Exception {
        List<String> param = this.queryActValueByTemplateId(actId, templateId);
        Template template = queryById(templateId);
        Mp t = new Mp();
        t.setAppId(wxAppId);
        List<Mp> mps = mpMapper.queryByExamplePage(t);
        if (CollectionUtils.isEmpty(mps)) {
            throw new BasicServiceException("appId " + wxAppId + " 无法获得对应小程序");
        }
        SendTempMessage sendTempMessage = new SendTempMessage();
        sendTempMessage.setParams(param);
        sendTempMessage.setOpenId(openId);
        sendTempMessage.setTemplateId(template.getTemplateId());
        sendTempMessage.setFormId(formId);
        sendTempMessage.setAppId(wxAppId);
        sendTempMessage.setAppSecret(mps.get(0).getAppSecret());
        sendTempMessage.setPageUrl(template.getAttr3());
        JSONObject jsonObject = sendTempMessageService.sendMpTemplate(sendTempMessage);
        logger.info("发送消息返回参数" + jsonObject);
        WxExceptionUtil.parse(jsonObject.toJSONString());
    }

    @Override
    public List<String> queryActValueByTemplateId(Long actId, Long templateId) throws Exception {
        Template template = getTemplate(actId, templateId);
        // 取值方法名
        String getMethodName = null;
        // 微信模板消息传值方法名
        String setMethodName = null;
        // 返回对象，存储了配置好的模板消息值
        TempData tempData = new TempData();
        List<String> param = new ArrayList<>(10);
        try {
            for (int i = 0; i < 10; i++) {
                // 当前游标，以1为起点
                int index = i + 1;
                getMethodName = "getParameter" + index;
                Method getMethod = Template.class.getMethod(getMethodName);
                Object obj = getMethod.invoke(template);
                if (obj == null) {
                    continue;
                }
                // tempTableId
                Long tableId = Long.valueOf(obj.toString());
                TemTable temTable = tableService.queryById(tableId);
                if (temTable == null) {
                    continue;
                }
                String tableName = temTable.getTable1();
                String columnName = temTable.getColumn1();
                // 查询对应表的对应字段值
                String value = this.queryTemplateValueByAct(actId, tableName, columnName);
                param.add(value);
            }
        } catch (NoSuchMethodException e) {
            String exceptionMethodName = setMethodName == null ? getMethodName : setMethodName;
            throw new BasicServiceException("不存在【" + exceptionMethodName + "】此方法");
        } catch (IllegalAccessException e) {
            String exceptionMethodName = setMethodName == null ? getMethodName : setMethodName;
            throw new BasicServiceException("【" + exceptionMethodName + "】方法执行失败");
        } catch (InvocationTargetException e) {
            String exceptionMethodName = setMethodName == null ? getMethodName : setMethodName;
            throw new BasicServiceException("【" + exceptionMethodName + "】方法执行失败");
        }
        return param;
    }

    /**
     * 校验数据，获得模板
     *
     * @author NingLanhao
     * @date 2019-08-20 11:14
     * @param bizId 业务主键
     * @param templateId 模板主键
     * @return com.hand.base.sms.model.Template
     */
    private Template getTemplate(Long bizId, Long templateId) throws Exception {
        if (null == bizId || null == templateId) {
            throw new BasicServiceException("信息不完善,无法查询");
        }
        Template template = queryById(templateId);
        if (template == null) {
            throw new BasicServiceException("未查询到ID为{" + templateId + "}的模板");
        }
        return template;
    }

    public String queryTemplateValueByAct(Long actId, String tableName, String columnName) throws Exception {
        String s = null;
        try {
            s = templateMapper.queryTemplateValueByAct(actId, tableName, columnName);
        } catch (BadSqlGrammarException e) {
            logger.error(e);
            throw new BasicServiceException("执行SQL失败，配置有误，请联系管理员");
        } catch (Exception e) {
            throw e;
        }
        return s;
    }
}
